//
//  XWAlamofireNetwork.swift
//  iOS-XiaWan
//
//  Created by Miles on 2023/10/10.
//  Copyright © 2023 turningsyn. All rights reserved.
//

import Alamofire
import UIKit

extension Notification.Name {
    public static let networkWithJWTTokenError = Notification.Name("NetworkWithJWTTokenError")
}

//MARK: - 网络请求状态码
enum XWResStatusCode: Int {
    case ResStatusSuccess          = 0  //请求成功
    case ResStatusInvaidToken      = 401  //Token过期
    case ResStatusTimeOut          = 502  //请求超时
}

extension XWResStatusCode {
    public var description: String! {
        switch self {
        case .ResStatusSuccess:
            return "成功"
        case .ResStatusInvaidToken:
            return "Token过期"
        case .ResStatusTimeOut:
            return "请求超时"
        }
    }
}

//MARK: - 请求异常基类
class XWBaseError: Error {
    var desc: String = ""
    var code: Int = 0
    var localizedDescription: String {
        return desc
    }
    
    init(_ desc: String?) {
        if (desc == nil) {
            self.desc = "服务器繁忙，请稍后再试~~~"
        } else {
            self.desc = desc!
        }
    }
    init(_ code: Int?) {
        if (code == nil) {
            self.code = -1
        } else {
            self.code = code!
        }
    }
    init(_ code: Int?, _ desc: String?) {
        if (desc == nil) {
            self.desc = "服务器繁忙，请稍后再试~~~"
        } else {
            self.desc = desc!
        }
        
        if (code == nil) {
            self.code = -1
        } else {
            self.code = code!
        }
    }
}
 
//MARK: - 网络请求类
public class XWAlamofireNetwork {

    
    //MARK: 封装get请求
    public class func requestGet(_ urlString: String,
                            parameters: Parameters? = nil,
                            headers: HTTPHeaders? = nil,
                           showError: Bool = true,
                           success: @escaping ([String : Any]) -> Void,
                            failure: @escaping (Any?) -> Void) -> Void {
        
        do {
            _ = try validateURL(BaseURL)
        } catch {
            fatalError("Invalid Base URL")
        }
        
        baseGetDataRequest(urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!, method: .get, parameters: parameters,showError: showError, success: success, failure: failure)

        /*  TOKEN 校验逻辑 暂不需要
        validateHTTPS()
        
        if isTokenExceptionApi(api: urlString) {
            sendRequest()
        } else {
            if tokenExpires() == true {
                getRefreshToken() {
                    sendRequest()
                }
            } else {
                sendRequest()
            }
        }
         
        func sendRequest() {
            var ssbHeaders:HTTPHeaders = ["Content-Type" : "application/json; charset=UTF-8","Form-type":"app","Authorization" : "Bearer " +  getSessionToken()]
            ssbHeaders = appendHttpHeader(httpHeaders: ssbHeaders)

            baseGetDataRequest(urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!, method: .get, parameters: parameters, headers: ssbHeaders,showError: showError, success: success, failure: failure)
        }
         */
    }
    
    public class func requestPost(_ urlString: String,
                               bodyJson: Any = [],
                               parameters: Parameters? = nil,
                               headers: HTTPHeaders? = nil,
                               showError: Bool = true,
                               success: @escaping ([String : Any]) -> Void,
                               failure: @escaping (Any?) -> Void) -> Void {
        do {
            _ = try validateURL(BaseURL)
        } catch {
            fatalError("Invalid Base URL")
        }
        
        if var bodyJsonParams = bodyJson as? [String : Any] {
            bodyJsonParams["deviceName"] = getDeviceName()
            bodyJsonParams["deviceVersion"] = getDeviceModel()
            let body = try? JSONSerialization.data(withJSONObject: bodyJsonParams, options: .prettyPrinted)
            baseHttpBodyDataRequest(urlString, method: .post, body: body, parameters: parameters, showError: showError, success: success, failure: failure)
        }else {
            let body = try? JSONSerialization.data(withJSONObject: bodyJson, options: .prettyPrinted)
            baseHttpBodyDataRequest(urlString, method: .post, body: body, parameters: parameters, showError: showError, success: success, failure: failure)
        }
        
        

        /*  TOKEN 校验逻辑 暂不需要
        validateHTTPS()
        let body = try? JSONSerialization.data(withJSONObject: bodyJson, options: .prettyPrinted)
        
        if isTokenExceptionApi(api: urlString) {
            sendRequest()
        } else {
            if tokenExpires() == true {
                getRefreshToken() {
                    sendRequest()
                }
            } else {
                sendRequest()
            }
        }
        
        func sendRequest() {
            baseHttpBodyDataRequest(urlString, method: .post, body: body, parameters: parameters, headers: headers, showError: showError, success: success, failure: failure)
        }
         */
    }
    
    public class func requestPut(_ urlString: String,
                               bodyJson: Any = [],
                               parameters: Parameters? = nil,
                               headers: HTTPHeaders? = nil,
                               showError: Bool = true,
                               success: @escaping ([String : Any]) -> Void,
                               failure: @escaping (Any?) -> Void) -> Void {
        do {
            _ = try validateURL(BaseURL)
        } catch {
            fatalError("Invalid Base URL")
        }
        let body = try? JSONSerialization.data(withJSONObject: bodyJson, options: .prettyPrinted)
        baseHttpBodyDataRequest(urlString, method: .put, body: body, parameters: parameters, headers: headers, showError: showError, success: success, failure: failure)

        /*  TOKEN 校验逻辑 暂不需要
        validateHTTPS()
        let body = try? JSONSerialization.data(withJSONObject: bodyJson, options: .prettyPrinted)
        
        if isTokenExceptionApi(api: urlString) {
            sendRequest()
        } else {
            if tokenExpires() == true {
                getRefreshToken() {
                    sendRequest()
                }
            } else {
                sendRequest()
            }
        }
        
        func sendRequest() {
            baseHttpBodyDataRequest(urlString, method: .post, body: body, parameters: parameters, headers: headers, showError: showError, success: success, failure: failure)
        }
         */
    }
    
    public class func requestDelete(_ urlString: String,
                               bodyJson: Any = [],
                               parameters: Parameters? = nil,
                               headers: HTTPHeaders? = nil,
                               showError: Bool = true,
                               success: @escaping ([String : Any]) -> Void,
                               failure: @escaping (Any?) -> Void) -> Void {
        do {
            _ = try validateURL(BaseURL)
        } catch {
            fatalError("Invalid Base URL")
        }
        let body = try? JSONSerialization.data(withJSONObject: bodyJson, options: .prettyPrinted)
        baseHttpBodyDataRequest(urlString, method: .delete, body: body, parameters: parameters, headers: headers, showError: showError, success: success, failure: failure)

        /*  TOKEN 校验逻辑 暂不需要
        validateHTTPS()
        let body = try? JSONSerialization.data(withJSONObject: bodyJson, options: .prettyPrinted)
        
        if isTokenExceptionApi(api: urlString) {
            sendRequest()
        } else {
            if tokenExpires() == true {
                getRefreshToken() {
                    sendRequest()
                }
            } else {
                sendRequest()
            }
        }
        
        func sendRequest() {
            baseHttpBodyDataRequest(urlString, method: .post, body: body, parameters: parameters, headers: headers, showError: showError, success: success, failure: failure)
        }
         */
    }
    
    private class func baseGetDataRequest(_ urlString: String,
                                          method: HTTPMethod,
                                          parameters: Parameters? = nil,
                                          headers: HTTPHeaders? = nil,
                                          showError: Bool = true,
                                          success: @escaping ([String : Any]) -> Void,
                                          failure: @escaping (Any?) -> Void) -> Void {
        let httpHeaers: HTTPHeaders!
        if headers == nil {
            httpHeaers = appendHttpHeader(sessionToken: getAccessToken())
        }else {
            httpHeaers = headers
        }
        Alamofire.request(URL(string: BaseURL+urlString)!,method: method, parameters: parameters, encoding: URLEncoding.default, headers:httpHeaers).responseJSON { response in
            
            XWLog(BaseURL+urlString)
            handleResponse(response: response, success: success, failure: failure, showError: showError)
        }
    }
    
    
    private class func baseHttpBodyDataRequest(_ urlString: String,
                                               method: HTTPMethod,
                                               body: Data? = nil,
                                               parameters: Parameters? = nil,
                                               headers: HTTPHeaders? = nil,
                                               showError: Bool = true,
                                               success: @escaping ([String : Any]) -> Void,
                                               failure: @escaping (Any?) -> Void) -> Void {
    
        var baseRequest = URLRequest(url: URL(string: BaseURL+urlString)!)
        baseRequest.httpMethod = method.rawValue
        baseRequest.httpBody = body
        // 统一的超时时间，若是想单独自定义，就得定义一个参数了
        baseRequest.timeoutInterval = 15
        let httpHeaers: [String: String]!
        if headers == nil {
            httpHeaers = appendHttpHeader(sessionToken: getAccessToken())
        }else {
            httpHeaers = headers
        }
        baseRequest.allHTTPHeaderFields = httpHeaers
        Alamofire.request(baseRequest).responseJSON { (response) in
            handleResponse(response: response, success: success, failure: failure, showError: showError)
        }
    }
    
    private class func handleResponse(response: DataResponse<Any>,
                                      success: @escaping ([String : Any]) -> Void,
                                      failure: @escaping (Any?) -> Void,
                                      showError: Bool) {
        XWLog(response)

        switch response.result {
        case .success(let value):
            guard let dataDic : Dictionary = value as? [String : Any] else { return }
            if !dataDic.keys.contains("code") { // 不包含code字段
                let error = XWBaseError.init(nil, dataDic["msg"] as? String)
                handleError(error: error, failure: failure, showError: showError) // 抛出error, 外面处理
                print(error.localizedDescription)
            } else if let code : Int = dataDic["code"] as? Int {
                if code == XWResStatusCode.ResStatusSuccess.rawValue { // 成功
                    success(dataDic)
                } else if code == XWResStatusCode.ResStatusInvaidToken.rawValue { // 登录态失效
                    outLogin()
                } else { // 其他异常
                    let error = XWBaseError.init(code, dataDic["msg"] as? String)
                    handleError(error: error, failure: failure, showError: showError) // 抛出error, 外面处理
                    print(error.localizedDescription)
                }
            }

        case .failure(let error):
            handleError(error: error, failure: failure, showError: showError)
        }
    }
    
    
    private class func handleError(error: Error,
                                   failure: @escaping (Any?) -> Void,
                                   showError: Bool) {
        var errorStr = ""
        if kNetworkStatus == "notReachable" { // 网络问题
            errorStr = "网络不可用"
        } else { // 非网络问题
            if let err = error as? XWBaseError {
                errorStr = err.localizedDescription
            } else {
                errorStr = error.localizedDescription
            }
        }
        
        // 隐藏原加载动画，并显示报错
        if showError {
            print(errorStr)
        }
        failure(error) // 抛出error, 外面处理
    }
    
    
    private class func outLogin() {
        NotificationCenter.default.post(name: .networkWithJWTTokenError, object: nil, userInfo: nil)
    }
    
    //MARK: 设置请求Header
    private class func appendHttpHeader(sessionToken: String) -> HTTPHeaders {
        let datetime = Date().string(withFormat: "yyyy-MM-dd HH:mm:ss")
        let currentLanguage: String = Locale.preferredLanguages.first?.components(separatedBy: "-").first ?? "en"
        var lang: String!
        if currentLanguage == "zh" {
            lang = "zh_CN"
        }else {
            lang = "en_US"
        }
        let headers:HTTPHeaders = [
            "Content-Type" : "application/json; charset=UTF-8",
            "Form-type":"app",
            "Authorization" : "Bearer " +  sessionToken,
            "Accept": "application/json",
            "appVersionCode": xwBuildVersion,
            "appVersionName": xwAppVersion,
            "os": "iOS",
            "datetime":datetime,
            "lang": lang
        ]
        return headers
    }

    
    //MARK: 验证HTTPS
    private class func validateHTTPS() {

        // 忽略本地缓存，重新获取，防止没更新json文件
        XWSessionManager.shareManager().session.configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
        XWSessionManager.shareManager().delegate.sessionDidReceiveChallenge = { session, challenge in
            var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
            var credential: URLCredential?
            
            if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
                disposition = URLSession.AuthChallengeDisposition.useCredential
                credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
            } else {
                if challenge.previousFailureCount > 0 {
                    disposition = .cancelAuthenticationChallenge
                } else {
                    credential = XWSessionManager.shareManager().session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)
                    if credential != nil {
                        disposition = .useCredential
                    }
                }
            }
            return (disposition, credential)
        }
    }
    
    //MARK:  判断token是否已过期
    private class func tokenExpires() -> Bool {
//        let exTimeStr = getSessionToken()
//        let exTime = exTimeStr.toDouble()
//        let cuTime = Double(Date().timeIntervalSince1970 * 1000)
//        let surSec = Int((exTime - cuTime)/1000)
//        let surTimeStr = "\(surSec/60)分 \(surSec%60)秒"
//        XWLog("token剩余时间：" + surTimeStr)
//        // 剩余时间小于10分钟，认为已过期
//        if exTime - cuTime < 10*60*1000 {
//            return true
//        } else {
            return false
//        }
    }
    
    //MARK:  判断api是否不需要检测token
    private class func isTokenExceptionApi(api: String) -> Bool {
#warning("TODO - 此处设置不需要验证Token 的 domain")
        let exceptionArr: [String] = [
//            RefreshToken
        ]
        for str in exceptionArr {
            if api.hasPrefix(str) {
                return true
            }
        }
        return false
    }
    
    //MARK: 刷新Token
    private class func getRefreshToken(complete:@escaping() -> Void = {}) {
//        let rToken = getSessionToken()
//        #warning("TODO - 补充刷新Token代码")
//        XWAlamofireNetwork.requestPost(kRefreshToken + "?refreshToken=\(rToken)", bodyJson: [], parameters: nil, headers: nil, showError: false, success: {(data) in
//            let code = data["code"] as! Int
//            if code == 0 {
//                //信息存储
//                if let dataDic : Dictionary = data["data"] as? [String : Any]{
//                    let jsonStr = xwDicValueString(dataDic)
//                    UserDefaults.standard.set(jsonStr, forKey: kXWUserTokenCacheKey)
//                    UserDefaults.standard.synchronize()
//                }
//            }
//        }) { (error) in
//            if let err = error as? XWBaseError {
//                let code = err.code
//                if code == 40101 {//RefreshToken过期
//                    outLogin()
//                }
//            }
//        }
    }
    
#if os(iOS)
    public class func uploadImageWithFormDataRequest(
        urlString: String,
        params:[String:Any]?,
        image: UIImage,
        success: @escaping ([String : Any]) -> Void,
        failure: @escaping (Any?) -> Void) {
            
            guard let md5Str = params?["Content-MD5"] as? String else {
                return
            }
            let requestHeader: HTTPHeaders = ["content-type" : "multipart/form-data","Content-MD5": md5Str]
            
            Alamofire.upload(multipartFormData: { (multipartFormData) in
                if params != nil {
                    for (key, value) in params! {
                        let data_ = "\(value)".data(using: String.Encoding.utf8)!
                        //                       print(msg)
                        multipartFormData.append(data_, withName: key)
                    }
                }
                
                if let imgData = image.jpegData(compressionQuality: 0.6) {
                    multipartFormData.append(imgData, withName: "file",fileName: "\(String(describing: params?["fileName"])).png", mimeType: "image/png")
                }
            }, to: URL(string: urlString)!, method: .put, headers: requestHeader) { (encodingResult) in
                
                switch encodingResult {
                case .success(let upload, _, _):
                    upload.responseJSON { response in
                        //debugPrint("upload-- \(response)")
                        /// 上传成功
                        guard response.result.isSuccess else {
                            /// 网络链接错误或者服务器故障
                            
                            return
                        }
                        
                        guard let dataDic : Dictionary = response.result.value as? [String : Any] else { return }
                        if let code : Int = dataDic["code"] as? Int{
                            success(dataDic)
                           if code == XWResStatusCode.ResStatusInvaidToken.rawValue { // 登录失效
                                outLogin()
                           }

                        }
                        
                    }
                case .failure(let encodingError):
                    print(encodingError)
                }
            }
    }
#endif
    
}
